package org.rainwalk.library.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.UUID;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.rainwalk.library.api.exception.BizException;
import org.rainwalk.library.api.model.ResponseCode;
import org.rainwalk.library.model.domain.BooleanResult;
import org.rainwalk.library.model.domain.SubFile;
import org.rainwalk.library.model.enums.FileType;
import org.rainwalk.library.service.IFileService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.constraints.NotEmpty;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * 文件服务抽象父类
 *
 * @author 趁雨行 2021-07-16 21:49:03
 */
@Slf4j
@Getter
@Setter
public abstract class FileServiceAbstract implements IFileService, InitializingBean {

    /**
     * 支持的文件拓展名
     */
    @NotEmpty(message = "文件拓展名不能为空")
    protected String fileExtension;

    /**
     * 文件存储目录
     */
    @NotEmpty(message = "文件存储目录不能为空")
    protected String storageDirectory;

    /**
     * 文件最大长度
     * 单位：B/KB/MB/GB
     */
    @NotEmpty(message = "文件最大长度不能为空")
    protected String maxSize;

    /**
     * 文件最大byte长度
     */
    private long maxSizeByte;

    @Override
    public BooleanResult<String> support(FileType fileType) {
        return new BooleanResult<>(fileType.getValue().equals(this.fileExtension), null);
    }

    @Override
    public File saveToDisk(MultipartFile multipartFile) throws IOException {
        String filename = UUID.fastUUID().toString()  + "." + this.getFileExtension();
        File file = new File(this.storageDirectory, filename);
        multipartFile.transferTo(file);
        BooleanResult<String> canParseResult = canParse(file);
        if (!canParseResult.isBool()) {
            file.delete();
            throw new BizException(ResponseCode.PARAMS_VERITY_FAIL, canParseResult.getInfo());
        }
        return processingFile(file);
    }

    @Override
    public BooleanResult<String> canParse(File file) {
        return new BooleanResult<>(FileUtil.size(file) <= this.maxSizeByte, String.format("文件长度大于%s！", this.maxSize));
    }

    /**
     * 对文件进行加工
     *
     * @param file 文件
     * @return file 加工后的文件
     */
    protected File processingFile(File file) {
        return file;
    }

    @Override
    public List<SubFile> splitFile(File file) throws IOException {
        List<SubFile> subFiles = new ArrayList<>();
        SubFile subFile = new SubFile();
        subFile.setSubNo("only");
        subFile.setFile(file);
        subFiles.add(subFile);
        return subFiles;
    }

    /**
     * 清除拆分文件时可能产生的资源
     *
     * @param file 主文件
     */
    @Override
    public void cleanResourceOnSplitFile(File file, List<SubFile> subFiles) {
    }

    @Override
    public Optional<File> fetchFile(String filename) {
        File file = FileUtil.file(this.storageDirectory, filename);
        if (!file.exists()) {
            Optional.empty();
        }
        return Optional.of(file);
    }

    @Override
    public void afterPropertiesSet() {
        File directory = new File(this.storageDirectory);
        if (directory.mkdirs()) {
            log.info("文件服务：创建{}文件存储目录: {}", this.fileExtension, this.storageDirectory);
        }
        this.maxSizeByte = resolveSizeProperties();
    }

    private long resolveSizeProperties() {

        if (this.maxSize.endsWith("KB")) {
            String length = this.maxSize.replaceFirst("KB", "");
            return Long.parseLong(length) * 1024L;
        }

        if (this.maxSize.endsWith("MB")) {
            String length = this.maxSize.replaceFirst("MB", "");
            return Long.parseLong(length) * 1024L * 1024L;
        }

        if (this.maxSize.endsWith("GB")) {
            String length = this.maxSize.replaceFirst("GB", "");
            return Long.parseLong(length) * 1024L * 1024L * 1024L;
        }
        if (this.maxSize.endsWith("B")) {
            String length = this.maxSize.replaceFirst("B", "");
            return Long.parseLong(length);
        }
        throw new IllegalArgumentException("文件长度属性[" + this.maxSize + "]有误！");
    }
}
